package controllers

import (
	"bytes"

	"net/http"
	"sort"
	"strconv"
	"time"

	"gitee.com/golanglearn/small/app"
	"gitee.com/golanglearn/small/models"
	"gitee.com/golanglearn/small/repositories"

	"github.com/gorilla/mux"
)

type TaskController struct {
	*app.App
	repositories.TaskRepository
	repositories.SubTaskRepository
	repositories.SceneRepository
	repositories.UserRepository
}

func NewTaskController(a *app.App, tr repositories.TaskRepository, str repositories.SubTaskRepository, sr repositories.SceneRepository, ur repositories.UserRepository) *TaskController {
	return &TaskController{a, tr, str, sr, ur}
}

func (tc *TaskController) GetByTid(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	tid, err := strconv.Atoi(vars["tid"])
	if err != nil {
		NewAPIError(&APIError{false, "Invalid request", http.StatusBadRequest}, w)
		return
	}
	task, err := tc.TaskRepository.FindByTid(tid)
	if err != nil {
		NewAPIError(&APIError{false, "Could not find task", http.StatusNotFound}, w)
		return
	}

	NewAPIResponse(&APIResponse{Success: true, Data: task}, w, http.StatusOK)
}

func (tc *TaskController) Create(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	tid, err := strconv.Atoi(vars["tid"])
	if err != nil {
		NewAPIError(&APIError{false, "Invalid request", http.StatusBadRequest}, w)
		return
	}

	_, err = tc.TaskRepository.FindByTid(tid)
	if err == nil {
		NewAPIError(&APIError{false, "Create only one task", http.StatusBadRequest}, w)
		return
	}

	scenes, err := tc.SceneRepository.GetAllOfUid(tid)
	if err != nil {
		NewAPIError(&APIError{false, "Could not fetch scenes", http.StatusBadRequest}, w)
		return
	}

	if len(scenes) < 2 {
		NewAPIError(&APIError{false, "At least two people attended", http.StatusBadRequest}, w)
		return
	}

	_, err = tc.SubTaskRepository.FindByTid(tid)
	if err != nil {
		NewAPIError(&APIError{false, "Must first create a subtask", http.StatusBadRequest}, w)
		return
	}

	var uids []int
	var buffer bytes.Buffer
	var uid int

	//生成UID Slice
	for _, v := range scenes {
		uids = append(uids, v.UID)
	}

	//UID 排序
	sort.Sort(sort.Reverse(sort.IntSlice(uids)))

	//拼接UID
	for _, v := range uids {
		s := strconv.Itoa(v)
		buffer.WriteString(s)
	}
	exec := buffer.String()

	task, err := tc.TaskRepository.FindByExec(exec)
	if err == nil {
		for i, v := range uids {
			if task.UID == v {
				if i+1 == len(uids) {
					uid = uids[0]
				} else {
					uid = uids[i+1]
				}
			}
		}
	} else {
		//直接按规则生成UID
		uid = uids[0]
	}

	uid, err = executor(uid, tc, uids)
	if err != nil {
		NewAPIError(&APIError{false, "Update status fail", http.StatusBadRequest}, w)
		return
	}

	task = &models.Task{
		TID:       tid,
		UID:       uid,
		Exec:      exec,
		CreatedAt: time.Now(),
	}

	err = tc.TaskRepository.Create(task)
	if err != nil {
		NewAPIError(&APIError{false, "Could not create task", http.StatusBadRequest}, w)
		return
	}

	// TODO: Change this maybe put the user object into a context and get the author from there.
	u, err := tc.UserRepository.FindById(uid)
	if err != nil {
		NewAPIError(&APIError{false, "Content is required", http.StatusBadRequest}, w)
		return
	}
	task.Executor = u.Name

	defer r.Body.Close()
	NewAPIResponse(&APIResponse{Success: true, Message: "Task created", Data: task}, w, http.StatusOK)
}

func executor(uid int, tc *TaskController, uids []int) (int, error) {
	id, err := tc.SubTaskRepository.FindByUid(uid)
	if err != nil || id == 0 {
		return uid, nil
	}
	for i, v := range uids {
		if uid == v {
			if i+1 == len(uids) {
				uid = uids[0]
			} else {
				uid = uids[i+1]
			}
			break
		}
	}
	err = tc.SubTaskRepository.UpdateStatus(id)
	if err != nil {
		return id, err
	}
	return executor(uid, tc, uids)
}
